#include <iostream>
#include <string>
#include <cstring>
#include <functional>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "Log.hpp"
#include "Thread.hpp"

using namespace log_ns;

int GetSockfd() {
    int local_socket = socket(AF_INET, SOCK_DGRAM, 0);
    if (local_socket < 0) {
        LOG(FATAL, "Create socket fail\n");
        exit(0);
    }
    LOG(INFO, "Create socket success\n");
    return local_socket;
}

void SendInfo(int local_socket, uint16_t server_port, const std::string& server_ip, const std::string& name) {
    struct sockaddr_in server;
    memset(&server, 0, sizeof(server));
    socklen_t len = sizeof(server);
    server.sin_family = AF_INET;
    server.sin_port = htons(server_port);
    server.sin_addr.s_addr = inet_addr(server_ip.c_str());

    while (true) {
        std::string info;
        std::cout << "Please input the info: ";
        std::getline(std::cin, info);
        if (info.size() > 0)
            // 将消息发送出去
            int num = sendto(local_socket, info.c_str(), info.size(), 0, (struct sockaddr *)&server, len);
        else
            break;
    }
}

void ReceiveInfo(int local_socket, const std::string& name) {
    while (true) {
        struct sockaddr_in temp;
        socklen_t len = sizeof(temp);
        char buff[1024];
        int recvlen = recvfrom(local_socket, buff, sizeof(buff) - 1, 0, (struct sockaddr *)&temp, &len);
        // 加锁的话还需要使用条件变量

        if (recvlen > 0)
        {
            buff[recvlen] = 0;
            std::cout << buff << std::endl;
        }
    }
}

// 客户端在未来一定要知道服务器的ip port
int main(int argc, char* args[]) {
    if (argc != 3) {
        LOG(ERROR, "please input the -> ./client、ip and port\n");
        return 0;
    }
    // 获取 ip 和 port 以及 socket
    uint16_t server_port = std::stoi(args[2]);
    std::string server_ip = args[1];

    int local_socket = GetSockfd();

    // 现在需要将发送消息和接收消息的函数绑定
    func_t send_func = std::bind(&SendInfo, local_socket, server_port, server_ip, std::placeholders::_1);
    func_t recev_func = std::bind(&ReceiveInfo, local_socket, std::placeholders::_1);

    Thread receive_thread(recev_func, "client receive");
    Thread send_thread(send_func, "client send");
    // 绑定服务器信息

    receive_thread.Start();
    send_thread.Start();

    receive_thread.Join();
    send_thread.Join();

    close(local_socket);
    return 0;
}